<?php
declare(strict_types = 1);

namespace IMOcean\Tests;

use Swoole\Server;
use Swoole\Http\Server as HttpServer;
use Swoole\Websocket\Server as WebSocketServer;

/**
 * Class Instance
 * @package IMOcean\Servers
 */
final class Instance
{
    /**
     * ip
     */
    const IP = '0.0.0.0';

    /**
     * port
     */
    const PORT = [
        'http' => 9501,
        'tcp' => 9502,
        'udp' => 9503,
        'websocket' => 9504,
    ];

    /**
     * start http serve
     *
     * @return bool
     */
    public static function httpServer(): bool
    {
        $key = 'http';

        $http = new HttpServer(self::IP, self::PORT[$key]);

        $http->on('Start', function ($http) use ($key) {
            echo "http server: {$key}://" . self::IP . ':' . self::PORT[$key] . PHP_EOL;
        });

        $http->on('Request', function ($request, $response) {
            $response->header('Content-Type', 'text/plain');

            $response->end('hello world');
        });

        return $http->start();
    }

    /**
     * start tcp serve
     *
     * @return bool
     */
    public static function tcpServer(): bool
    {
        $key = 'tcp';

        $tcp = new Server(self::IP, self::PORT[$key]);

        $tcp->on('Start', function ($tcp) use ($key) {
            echo "tcp server: {$key}://" . self::IP . ':' . self::PORT[$key] . PHP_EOL;
        });

        $tcp->on('Connect', function ($tcp, $socketId) {
            echo "connection open socket file description sign: {$socketId}" . PHP_EOL;
        });

        $tcp->on('Receive', function ($tcp, $socketId, $reactorId, $data) {
            $tcp->send($socketId, "response: {$data}");
        });

        $tcp->on('Close', function ($tcp, $socketId) {
            echo "connection close socket file description sign: {$socketId}" . PHP_EOL;
        });

        return $tcp->start();
    }

    /**
     * start udp serve
     *
     * @return bool
     */
    public static function udpServer(): bool
    {
        $key = 'udp';

        $udp = new Server(self::IP, self::PORT[$key], SWOOLE_PROCESS, SWOOLE_SOCK_UDP);

        $udp->on('Start', function ($udp) use ($key) {
            echo "udp server: {$key}://" . self::IP . ':' . self::PORT[$key] . PHP_EOL;
        });

        $udp->on('Packet', function ($udp, $data, $clientInformation) {
            echo "accept data from: ip => {$clientInformation['address']}, port => {$clientInformation['port']}" . PHP_EOL;

            $udp->sendTo($clientInformation['address'], $clientInformation['port'], "response: $data");
        });

        return $udp->start();
    }

    /**
     * start tcp serve
     *
     * @return bool
     */
    public static function webSocketServer(): bool
    {
        $key = 'websocket';

        $websocket = new WebSocketServer(self::IP, self::PORT[$key]);

        $websocket->on('Start', function ($websocket) use ($key) {
            echo "websocket server: {$key}://" . self::IP . ':' . self::PORT[$key] . PHP_EOL;
        });

        $websocket->on('Open', function ($websocket, $request) {
            echo "connection open socket file description sign: {$request->fd}" . PHP_EOL;
        });

        $websocket->on('Message', function ($websocket, $frame) {
            echo "receive message: {$frame->data}" . PHP_EOL;

            $websocket->push($frame->fd, "response: {$frame->data}");
        });

        $websocket->on('Close', function ($websocket, $socketId) {
            echo "connection close socket file description sign: {$socketId}" . PHP_EOL;
        });

        $websocket->on('Request', function ($request, $response) {
            $response->header('Content-Type', 'text/plain');

            $response->end('hello world');
        });

        return $websocket->start();
    }
}
